package pattern.bio_httpserver;

import howtomcatworks.ex01.Request;
import lombok.Data;
import org.apache.commons.lang3.StringUtils;

import java.io.*;
import java.util.HashMap;
import java.util.Map;

/**
 * @author xiawen yang
 * @date 2021/12/16 下午3:36
 */
public class HttpMessageParser {


    /**
     * 解析请求行
     * @param br
     * @param request
     */
    private static void decodeRequestLine(BufferedReader br, Request request) throws IOException {
        String[] strArr = StringUtils.split(br.readLine(), " ");
        assert strArr.length == 3;
        request.setMethod(strArr[0]);
        request.setUri(strArr[1]);
        request.setVersion(strArr[2]);
    }

    /**
     * 解析请求头
     * @param br
     * @param request
     */
    private static void decodeRequestHeader(BufferedReader br, Request request) throws IOException {
        Map<String, String> headers = new HashMap<>(16);
        String line = br.readLine();
        String[] kv;
        while (!"".equals(line)) {
            kv = StringUtils.split(line, ":");
            assert kv.length == 2;
            headers.put(kv[0].trim(), kv[1].trim());
            line = br.readLine();
        }

        request.setHeaders(headers);
    }

    /**
     * 解析正文
     * @param br
     * @param request
     */
    private static void decodeRequestMessage(BufferedReader br, Request request) throws IOException {
        int contentLen = Integer.parseInt(request.getHeaders().getOrDefault("Content-Length", "0"));
        if (contentLen == 0) {
            // 表示没有message，直接返回
            // 如get/options请求就没有message
            return;
        }

        char[] message = new char[contentLen];
        br.read(message);
        request.setMessage(new String(message));
    }


    /**
     *
     * @param request 请求对象
     * @param response 响应消息，用于构建响应体
     * @return
     */
    public static String buildResponse(Request request, String response) {
        Response httpResponse = new Response();
        httpResponse.setCode(200);
        httpResponse.setStatus("ok");
        httpResponse.setVersion(request.getVersion());

        Map<String, String> headers = new HashMap<>();
        headers.put("Content-Type", "application/json");
        headers.put("Content-Length", String.valueOf(response.getBytes().length));
        httpResponse.setHeaders(headers);
        httpResponse.setMessage(response);

        StringBuilder builder = new StringBuilder();
        buildResponseLine(httpResponse, builder);
        buildResponseHeaders(httpResponse, builder);
        buildResponseMessage(httpResponse, builder);
        return builder.toString();
    }

    private static void buildResponseLine(Response response, StringBuilder sb) {
        sb.append(response.getVersion()).append(" ").append(response.getCode()).append(" ")
                .append(response.getStatus()).append("\n");
    }

    private static void buildResponseHeaders(Response response, StringBuilder sb) {
        for (Map.Entry<String, String> entry : response.getHeaders().entrySet()) {
            sb.append(entry.getKey()).append(":").append(entry.getValue()).append("\n");
        }
        sb.append("\n");
    }

    private static void buildResponseMessage(Response response, StringBuilder sb) {
        sb.append(response.getMessage());
    }

    public static Request parse2Request(InputStream requestInputStream) throws IOException {
        BufferedReader br = new BufferedReader(new InputStreamReader(requestInputStream, "UTF-8"));
        Request httpRequest = new Request();
        decodeRequestLine(br, httpRequest);
        decodeRequestHeader(br, httpRequest);
        decodeRequestMessage(br, httpRequest);
        return httpRequest;
    }

    public static class Request {

        private String method;

        private String uri;

        private String version;

        private Map<String, String> headers;
        /**
         * 正文
         */
        private String message;

        public String getMethod() {
            return method;
        }

        public void setMethod(String method) {
            this.method = method;
        }

        public String getUri() {
            return uri;
        }

        public void setUri(String uri) {
            this.uri = uri;
        }

        public String getVersion() {
            return version;
        }

        public void setVersion(String version) {
            this.version = version;
        }

        public Map<String, String> getHeaders() {
            return headers;
        }

        public void setHeaders(Map<String, String> headers) {
            this.headers = headers;
        }

        public String getMessage() {
            return message;
        }

        public void setMessage(String message) {
            this.message = message;
        }
    }

    private static class Response {

        private String version;

        private int code;

        private String status;

        private Map<String, String> headers;

        private String message;

        public String getVersion() {
            return version;
        }

        public void setVersion(String version) {
            this.version = version;
        }

        public int getCode() {
            return code;
        }

        public void setCode(int code) {
            this.code = code;
        }

        public String getStatus() {
            return status;
        }

        public void setStatus(String status) {
            this.status = status;
        }

        public Map<String, String> getHeaders() {
            return headers;
        }

        public void setHeaders(Map<String, String> headers) {
            this.headers = headers;
        }

        public String getMessage() {
            return message;
        }

        public void setMessage(String message) {
            this.message = message;
        }
    }
}
